package la.foton.homebroker.negocio.service;

import java.math.BigDecimal;
import java.util.Date;

import la.foton.homebroker.integracao.cblc.CBLCAdapter;
import la.foton.homebroker.integracao.cblc.dto.RegistroAcaoDTO;
import la.foton.homebroker.integracao.megabolsa.MegaBolsaAdapter;
import la.foton.homebroker.integracao.megabolsa.dto.ExecucaoOrdemDTO;
import la.foton.homebroker.negocio.dao.OrdemDAO;
import la.foton.homebroker.negocio.entidade.Acao;
import la.foton.homebroker.negocio.entidade.Cotacao;
import la.foton.homebroker.negocio.entidade.Investidor;
import la.foton.homebroker.negocio.entidade.Ordem;
import la.foton.homebroker.negocio.entidade.enumeracoes.TipoOperacao;
import la.foton.homebroker.negocio.validador.ViolacaoNegocioException;
import la.foton.homebroker.negocio.validador.padrao.PadraoInvalidoException;

public class OrdemService {

	private CotacaoService cotacaoService;
	private AcaoService acaoService;
	private CarteiraService carteiraService;
	private MegaBolsaAdapter megaBolsaAdapter;
	private CBLCAdapter cblcAdapter;
	private OrdemDAO ordemDao;

	private void autorizaCompra(Ordem ordem, Investidor investidor)
			throws ViolacaoNegocioException {
		BigDecimal valorFinanceiro = ordem.getValorFinanceiroSolicitado();
		BigDecimal taxaCorretagem = ordem.getTaxaCorretagem(valorFinanceiro);

		if (investidor.getConta().getSaldo()
				.compareTo(valorFinanceiro.add(taxaCorretagem)) < 0)
			throw new ViolacaoNegocioException(
					"Saldo insuficiente pra realizar essa operação");

	}

	private void autorizaVenda(Ordem ordem, Investidor investidor)
			throws ViolacaoNegocioException {
		carteiraService.validaQuantidade(investidor, ordem);

		BigDecimal valorFinanceiro = ordem.getValorFinanceiroSolicitado();
		BigDecimal taxaCorretagem = ordem.getTaxaCorretagem(valorFinanceiro);

		if (investidor.getConta().getSaldo().compareTo(taxaCorretagem) < 0)
			throw new ViolacaoNegocioException(
					"Saldo insuficiente pra realizar essa operação");

	}

	public Cotacao consultaCotacao(String codigoAcao)
			throws PadraoInvalidoException {

		Acao acao = acaoService.obtemAcao(codigoAcao);

		return cotacaoService.consulta(acao, new Date());
	}

	public void autorizaRegistroOrdem(Ordem ordem, Investidor investidor)
			throws ViolacaoNegocioException {

		Cotacao cotacao = consultaCotacao(ordem.getAcao().getCodigo());
		ordem.valida(cotacao);

		// Verificar que uso terá a variação da cotação
		BigDecimal variacao = cotacao.getVariacao();

		if (ordem.getTipoOperacao() == TipoOperacao.COMPRA) {
			autorizaCompra(ordem, investidor);
		} else {
			autorizaVenda(ordem, investidor);
		}
	}

	public int confirmaRegistroOrdem(Ordem ordem, Investidor investidor,
			String senhaDigitada) throws ViolacaoNegocioException {
		investidor.verificaSenhaInformada(senhaDigitada);

		int quantidadeAcoesExecutadas = megaBolsaAdapter
				.solicitaExecucao(ExecucaoOrdemDTO.criaSolicitacao(ordem,
						investidor));
		if (quantidadeAcoesExecutadas > 0)
			cblcAdapter.informaExecucaoOrdem(RegistroAcaoDTO.criaSolicitacao(
					ordem, investidor, quantidadeAcoesExecutadas));

		ordem.registraQuantidadeExecutada(quantidadeAcoesExecutadas);

		if (ordem.getTipoOperacao() == TipoOperacao.COMPRA) {
			confirmaCompra(ordem, investidor);
		} else {
			confirmaVenda(ordem, investidor);
		}

		ordemDao.save(ordem);
		carteiraService.atualizaPosicao(investidor, ordem);

		return quantidadeAcoesExecutadas;
	}

	private void confirmaCompra(Ordem ordem, Investidor investidor) {
		BigDecimal valorFinanceiro = ordem.getValorFinanceiroExecutado();
		BigDecimal taxaCorretagem = ordem.getTaxaCorretagem(valorFinanceiro);

		investidor.getConta().debita(valorFinanceiro.add(taxaCorretagem));
	}

	private void confirmaVenda(Ordem ordem, Investidor investidor) {
		BigDecimal valorFinanceiro = ordem.getValorFinanceiroExecutado();
		BigDecimal taxaCorretagem = ordem.getTaxaCorretagem(valorFinanceiro);

		investidor.getConta().credita(valorFinanceiro.subtract(taxaCorretagem));
	}

}
